package com.sos.core
{
	import com.sos.utils.ClassUtils;

	public class Position
	{

		// -------------------------------------------------------------------------------
		// CONSTANTS
		// -------------------------------------------------------------------------------		
		
		public static const GOALKEEPER:Position			= new Position(1, 	"gk",		"Goalkeeper");
		public static const DEFENDER_01:Position		= new Position(2, 	"d1", 		"Defender 1");
		public static const DEFENDER_02:Position		= new Position(3, 	"d2", 		"Defender 2");
		public static const MIDFIELD:Position			= new Position(4, 	"mf", 		"Midfield");
		public static const FORWARD_01:Position			= new Position(5, 	"f1", 		"Forward 1");
		public static const FORWARD_02:Position			= new Position(6, 	"f2", 		"Forward 2");
		public static const SUB_DEFENCE:Position		= new Position(9, 	"sub_df", 	"Subst. Defence");
		public static const SUB_MIDFIELD:Position		= new Position(10,	"sub_mf", 	"Subst. Midfield");
		public static const SUB_FORWARD:Position		= new Position(11, 	"sub_fw", 	"Subst. Forward");
		
		public static const ANY:Position				= new Position(99, 	"any", 		"Any position");
		
		// -------------------------------------------------------------------------------
		// STATIC
		// -------------------------------------------------------------------------------
		
		private static var _initialized:Boolean = false;
		private static var _list:Vector.<Position>;
		
		// Fake static constructor
		{
			// Fill the internal list
			_list = new Vector.<Position>();
			_list.push(Position.GOALKEEPER);
			_list.push(Position.DEFENDER_01);
			_list.push(Position.DEFENDER_02);
			_list.push(Position.MIDFIELD);
			_list.push(Position.FORWARD_01);
			_list.push(Position.FORWARD_02);
			_list.push(Position.SUB_DEFENCE);
			_list.push(Position.SUB_MIDFIELD);
			_list.push(Position.SUB_FORWARD);
			// Init!
			_initialized = true;
		}
		
		// -------------------------------------------------------------------------------
		// FIELDS
		// -------------------------------------------------------------------------------
		
		private var _id:uint;
		private var _name:String;
		private var _sign:String;
		
		// -------------------------------------------------------------------------------
		// CONSTRUCTORS
		// -------------------------------------------------------------------------------
		
		public function Position(id:uint, sign:String, name:String)
		{
			// Safe unique instance lock
			if (_initialized) throw new Error("PlayerRole enum already created!");
			// Init
			_id    = id;
			_name  = name;
			_sign  = sign;
		}
		
		// -------------------------------------------------------------------------------
		// PROPERTIES
		// -------------------------------------------------------------------------------		
		
		public function get id():uint
		{
			return _id;
		}
		
		public function get sign():String
		{
			return _sign;
		}
		
		public function get name():String
		{
			return _name;
		}
		
		public function get isSubstitution():Boolean
		{
			return	_id == Position.SUB_DEFENCE.id ||
					_id == Position.SUB_MIDFIELD.id ||
					_id == Position.SUB_FORWARD.id;
		}
		
		// -------------------------------------------------------------------------------
		// PUBLIC METHODS
		// -------------------------------------------------------------------------------
		
		public function toString():String
		{
			return ClassUtils.getName(this) + "." + _name;
		}
		
		// -------------------------------------------------------------------------------
		// STATIC METHODS
		// -------------------------------------------------------------------------------
		
		/**
		 * Returns the list of the names of 
		 * @return 
		 */
		public static function names():Array
		{
			var list:Array  = new Array;
			// Loop over values list
			for (var i:int=0; i<_list.length; i++)
			{
				list.push(_list[i].name);
			}
			return list;
		}
		
		/**
		 * 
		 * @return 
		 */
		public static function list():Array
		{
			var list:Array = new Array;
			// Loop over values list
			for (var i:int=0; i<_list.length; i++)
			{
				list.push(_list[i]);
			}
			return list;
		}
		
		/**
		 * Search a Position by given id 
		 * @param id Id of the position to find
		 * @return Position constant for the given id, null if no Position
		 * for the given id has been found
		 */		
		public static function getById(id:uint):Position
		{
			// Search the value into the list
			for (var i:int=0; i<_list.length; i++)
			{
				if (_list[i].id == id) return _list[i];
			}
			throw new Error("Position for id '" + id + "' unknown!");
		}
		
		/**
		 * Search a Position by given name 
		 * @param name Name of the position to find
		 * @return Position constant for the given id, null if no Position
		 * for the given name has been found
		 */		
		public static function getByName(name:String):Position
		{
			// Search the value into the list
			for (var i:int=0; i<_list.length; i++)
			{
				if (_list[i].name == name) return _list[i];
			}
			throw new Error("Position for name '" + name + "' unknown!");
		}
		
		/**
		 * Search a Position by given sign 
		 * @param name sign of the player role to find
		 * @return Position constant for the given id, null if no Position
		 * for the given sign has been found
		 */		
		public static function getBySign(sign:String):Position
		{
			// Search the value into the list
			for (var i:int=0; i<_list.length; i++)
			{
				if (_list[i].sign == sign) return _list[i];
			}
			throw new Error("Position for name '" + sign + "' unknown!");
		}		
	
		/**
		 * Returns the opposed position of the given one  
		 * @param position Position
		 * @return Opposed position
		 * 
		 */		
		public static function getOpposite(position:Position):Position
		{
			var opposite:Position;
			switch (position)
			{
				case Position.DEFENDER_01:	opposite = Position.FORWARD_01;		break;
				case Position.DEFENDER_02:	opposite = Position.FORWARD_02;		break;
				case Position.MIDFIELD:		opposite = Position.MIDFIELD;		break;
				case Position.FORWARD_01:	opposite = Position.DEFENDER_01;	break;
				case Position.FORWARD_02:	opposite = Position.DEFENDER_02;	break;
				default:
					throw new Error("Position " + position +  "have not an opposite position");
			}
			return opposite;
		}
		
		/**
		 * Returns the opposed position of the given one  
		 * @param position Position
		 * @return Opposed position
		 */
		public static function getDefaultTarget(position:Position):Position
		{
			var opposite:Position;
			switch (position)
			{
				case Position.DEFENDER_01:	opposite = Position.MIDFIELD;		break;
				case Position.DEFENDER_02:	opposite = Position.MIDFIELD;		break;
				case Position.MIDFIELD:		opposite = Position.FORWARD_01;		break;
				case Position.FORWARD_01:	opposite = Position.MIDFIELD;		break;
				case Position.FORWARD_02:	opposite = Position.MIDFIELD;		break;
				default:
					throw new Error("Position " + position +  "have not an opposite position");
			}
			return opposite;
		}
		
		/**
		 * Returns the opposed position of the given one  
		 * @param position Position
		 * @return Opposed position
		 */
		public static function getNearbyPositions(position:Position):Vector.<Position>
		{
			var positions:Vector.<Position> = new Vector.<Position>();
			switch (position)
			{
				case Position.DEFENDER_01:
					positions.push(Position.DEFENDER_02);
					positions.push(Position.MIDFIELD);
					positions.push(Position.FORWARD_01);
					break;
				case Position.DEFENDER_02:
					positions.push(Position.DEFENDER_01);
					positions.push(Position.MIDFIELD);
					positions.push(Position.FORWARD_02);
					break;
				case Position.MIDFIELD:
					positions.push(Position.DEFENDER_01);
					positions.push(Position.DEFENDER_02);
					positions.push(Position.FORWARD_01);
					positions.push(Position.FORWARD_02);
					break;
				case Position.FORWARD_01:
					positions.push(Position.DEFENDER_01);
					positions.push(Position.MIDFIELD);
					positions.push(Position.FORWARD_02);
					break;
				case Position.FORWARD_02:
					positions.push(Position.DEFENDER_02);
					positions.push(Position.MIDFIELD);
					positions.push(Position.FORWARD_01);
					break;
				default:
					throw new Error("Position " + position +  "have not an reachable position");
			}
			return positions;
		}
		
	}
}